import os
import pathlib
import sys

project_path = pathlib.Path(os.path.abspath(__file__)).parent.parent.parent
sys.path.append(str(project_path))
from utility.import_log import flog
import shell.knowledge_graph.question_classifier as qc
import shell.knowledge_graph.cypher_search as cs

log = flog(__file__)

min_difference = 0.1


class AnswerFilter(object):
    def __init__(self, value_list: list, attr_list: list):
        self.value_list = value_list
        self.attr_list = attr_list

    def filter_by_nodes(self, question, clsfr: qc.Classifier):
        assert isinstance(clsfr, qc.Classifier), "clsfr should be Classifier object"

        log.info(f'预测左右节点名:{question}')
        node1_name, node2_name = clsfr.predict(question)
        log.info(f'预测结果: 左节点: {node1_name}, 右节点: {node2_name}')

        if node2_name == 'None':
            node2_name = node1_name

        new_value_list = []
        for each in self.value_list:
            if each['table'] == node1_name:
                new_value_list.append(each)

        new_attr_list = []
        for each in self.attr_list:
            if each['table'] == node2_name:
                new_attr_list.append(each)

        if new_value_list:
            self.value_list = new_value_list
        if new_attr_list:
            self.attr_list = new_attr_list

        self.node1_name = node1_name
        self.node2_name = node2_name

    def filter_by_shortestpath(self, cstemplate: cs.CypherSearch):
        assert isinstance(cstemplate, cs.CypherSearch), "cstemplate should be CypherSearch object"

        # filter identical value/attr using cypher shortest path
        new_value = None
        new_attr = None
        attr_score_list = [i['score'] for i in self.attr_list]

        if len(self.value_list) > 1 or (
                len(attr_score_list) > 1 and abs(attr_score_list[0] - attr_score_list[1]) < min_difference):
            # 若多个属性值score相同或多个属性名score相近，则使用最短路径方法过滤

            new_attr_list = []
            if (len(attr_score_list) > 1 and abs(
                    attr_score_list[0] - attr_score_list[1]) < min_difference):  # identical attr score
                # 多个属性名score相近的集合
                first_score = None
                for each in self.attr_list:
                    if first_score is None:
                        first_score = each['score']
                        new_attr_list.append(each)
                    else:
                        if abs(each['score'] - first_score) < min_difference:
                            new_attr_list.append(each)
            else:  # different attr score
                # 若多个属性名score不同，则取top1
                self.attr_list = [self.attr_list[0]]

            if len(new_attr_list):
                self.attr_list = new_attr_list

            # 从多个属性值相同或多个属性名相近的组合中，根据最短路径选择最终的属性值和属性名
            min_degree = 999
            for each_v in self.value_list:
                for each_a in self.attr_list:
                    cstemplate.template_match(each_v, each_a)
                    if cstemplate.degree_number is not None and cstemplate.degree_number < min_degree:
                        min_degree = cstemplate.degree_number
                        new_value = each_v
                        new_attr = each_a

        if new_value is not None:
            self.value_list = [new_value]
            self.attr_list = [new_attr]
